/***************************************************************************
 *   Copyright (C) 2007 by saa   *
 *   root@saa   *
 ***************************************************************************/
#include "tracerouteresultparser.h"
#include "compilemode.h"

TracerouteResultParser::TracerouteResultParser (QObject * parent) : QThread(parent),
    ipPattern("(\\s?|^?|\\()?(?:[0-1]?\\d?\\d|2[0-4]\\d|25[0-5])\\.(?:[0-1]?\\d?\\d|2[0-4]\\d|25[0-5])\\.(?:[0-1]?\\d?\\d|2[0-4]\\d|25[0-5])\\.(?:[0-1]?\\d?\\d|2[0-4]\\d|25[0-5])(\\)?|\\s?)"),
    twoDigitNumberParrern("\\b^\\d\\d?\\b"),
    asnPattern("\\[AS \\d\\d?\\d?\\d?\\d?\\]"),
    fiveDigitNumberPattern("\\b\\d\\d?\\d?\\d?\\d?\\b"),
    timePattern("(\\d\\d?\\d?\\d?\\d?.?\\d?\\d?\\d?\\smsec)"),
    taciturnHostPattern("(\\d\\s\\*\\s\\*\\s\\*)"),
    mplsPattern("(:?\\[?MPLS: Label \\d\\d?\\d?\\d?\\d?\\d?\\d? Exp \\d?\\d?\\]?)")
{
    
}


void TracerouteResultParser::run()
{
    QThread::exec();
}
    
void TracerouteResultParser::parseTracerouteResult(const QString &tracerouteResult)
{
    
#ifdef DEBUG
    log(tracerouteResult, LogFlag::Parser_DEBUG);
#endif

    QList<tracerouteNode> tracerouteNodeList;
    log("result parsing started");

    QStringList stringList(tracerouteResult.split("\n"));

    while(!stringList.isEmpty()){
        string = (stringList.takeFirst());
        string = string.trimmed();

#ifdef DEBUG
    log(string, LogFlag::Parser_DEBUG);
#endif

        if (string.indexOf("traceroute ") != -1 ||
            string.indexOf("Translating ") != -1 ||
            string == "Type escape sequence to abort." ||
            string.indexOf("Tracing the route to ") != -1 ||
            string.isEmpty())
            continue;

        //FIXME Qt bug! "Segmentation fault!" at taciturnHostPattern.indexIn(string) or string.indexOf(taciturnHostPattern)
        //if(taciturnHostPattern.indexIn(string) != -1)
            //continue;
        
        bool ttlTrue;
        int ttl(checkTTL().toInt(&ttlTrue));
        QString hostIP(checkIP());
        QString asNumber(checkASN());
        QString mpls(checkMPLS());// TODO check!
        QStringList tripTime(checkTripTime());
        //now string == hostName; TODO check *

#ifdef DEBUG
        log(QString("%1 %2 %3 %4 %5").arg(ttl).arg(string).arg(hostIP).arg(asNumber).arg(mpls), LogFlag::Parser_DEBUG);
        for(int i = 0; i < tripTime.size(); ++i)
            log(tripTime.at(i), LogFlag::Parser_DEBUG);
#endif
        

        if(hostIP.isEmpty() && stringList.isEmpty()) // wrong traceroute output end
            break;
        
        if(tripTime.isEmpty()){ // for taciturnHost, such as '3 * * *'
            tripTime.append("0");
            if(hostIP.isEmpty() && string != "* * *")
                continue;
        }

        int start = 0;
        if(ttlTrue && ttl >= tracerouteNodeList.size()){
            tracerouteNodeList.append(tracerouteNode(ttl, hostIP, string, asNumber, tripTime.at(0)));
            start = 1;
        }
        if(!tracerouteNodeList.isEmpty())
            for(int i = start; i < tripTime.size(); ++i)    
                tracerouteNodeList.last().append(tracerouteNodeList.last().ttl.at(0), hostIP, string, asNumber, tripTime.at(i));
    }
#ifdef DEBUG
    for (int i = 0; i < tracerouteNodeList.size(); ++i) {
        for(int j = 0; j < tracerouteNodeList.at(i).hostIP.size(); ++j){
            log(QString("%1 %2 %3 %4 %5").\
                    arg(tracerouteNodeList.at(i).ttl.at(j)).\
                    arg(tracerouteNodeList.at(i).hostName.at(j)).\
                    arg(tracerouteNodeList.at(i).hostIP.at(j)).\
                    arg(tracerouteNodeList.at(i).asn.at(j)).\
                    arg(tracerouteNodeList.at(i).tripTime.at(j)), LogFlag::Parser_DEBUG);
        }
    }
#endif
    log("result parsing finished");
    emit parsingFinished(tracerouteNodeList);
#ifndef ONE_THREAd
    quit();
#endif
}


QString TracerouteResultParser::checkTTL()
{
    QString routerNumber;
    int numberIndex(string.indexOf(twoDigitNumberParrern));
    if(!numberIndex){
        routerNumber = twoDigitNumberParrern.cap(0);
        cutString(numberIndex, twoDigitNumberParrern);
    }
    return routerNumber;
}

QString TracerouteResultParser::checkIP()
{
    QString hostIP;
    int ipIndex(string.indexOf(ipPattern));
    if(ipIndex != -1){
        hostIP = ipPattern.cap(0);
        hostIP = hostIP.remove("(");
        hostIP = hostIP.remove(")");
        cutString(ipIndex, ipPattern);
    }
    return hostIP;
}

QString TracerouteResultParser::checkASN()
{
    QString asNumber;
    int asnIndex(string.indexOf(asnPattern));
    if(asnIndex != -1){
        asNumber = asnPattern.cap(0);
        asNumber.indexOf(fiveDigitNumberPattern);
        asNumber = fiveDigitNumberPattern.cap(0);
        cutString(asnIndex, asnPattern);
    }
    return asNumber;
}

QStringList TracerouteResultParser::checkTripTime()
{
    //calculate trip average time
    QStringList tripTime;
    int timeIndex = string.indexOf(timePattern);
    while (timeIndex != -1) {
        QString tmp = timePattern.cap(0);
        tripTime.append((timePattern.cap(0)).remove(" msec"));
        cutString(timeIndex, timePattern);
        timeIndex = string.indexOf(timePattern);
    }
    return tripTime;
}

QString TracerouteResultParser::checkMPLS()
{
    QString mpls;
    //FIXME possible Qt bug: segmetation fault if create mplsPattern in constructor
    QRegExp mplsPattern("(:?\\[?MPLS: Label \\d\\d?\\d?\\d?\\d?\\d?\\d? Exp \\d?\\d?\\]?)");
    int mplsIndex = (string.indexOf(mplsPattern));
    if(mplsIndex != -1){
        mpls = mplsPattern.cap(0);
        cutString(mplsIndex, mplsPattern);
    }
    return mpls;
}

void TracerouteResultParser::cutString(const int index, const QRegExp & pattern)
{
    if(index >= 0 && index < string.size()){
        string = string.remove(index, pattern.matchedLength());
        string = string.trimmed();
    }
}

void TracerouteResultParser::log(const QString & message, const LogFlag::LogLevels logLevel) const
{
    emit logParserMessage(QString("parser: ") + message, logLevel);
}
